// 1.使用var,输出3,3,3
// 在这个循环中，var关键字声明的变量i具有函数作用域（在这个例子中是全局作用域）。
// 这意味着，尽管循环体内部每次迭代都会给i赋一个新值（1,2,3），但所有setTimeout回调中的闭包共享同一个i变量。
// 当setTimeout的回调函数执行时，循环已经结束，变量i的最终值已经被确定。因此所有的setTimeout回调都会打印3。
for (var i = 0; i < 3; i++) {
    setTimeout(() => {
        console.log(i);
    }, 0)
}

// 2.使用let,输出0,1,2
// 在这个循环中，let关键字声明的变量i具有块作用域（这里是for循环的每次迭代的作用域）。
// 这意味着每次循环迭代时，i都是一个新的、独立的变量。
// 因此，每个setTimeout回调都会捕获其各自迭代中i的当前值（分别是1, 2, 3）。
for (let j = 0; j < 3; j++) {
    setTimeout(() => {
        console.log(j);
    }, 0)
}


// 通过立即执行函数解决var在循环中闭包的问题
// 输出0,1,2
for (var j = 0; j < 3; j++) {
    (function(arg) {
        setTimeout(() => {
            console.log(arg);
        }, 0)
    })(j);
}

// 通过封装成单独的函数也能解决var在循环中闭包的问题
// 输出0,1,2
for (var j = 0; j < 3; j++) {
    fn(j)
}

function fn(n) {
    setTimeout(() => {
        console.log(n);
    }, 0)
}